package com.moming.douapisdk.client;

import com.moming.douapisdk.ApiException;
import com.moming.douapisdk.ApiRuntimeException;
import com.moming.douapisdk.BaseDouYinResponse;
import com.moming.douapisdk.DouYinRequest;
import com.moming.douapisdk.response.OauthResponse;
import com.moming.douapisdk.storage.IDouYinConfigStorage;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.Lock;

/**
 * 自用型应用客户端
 *
 * 无需传递token，自动维护token的有效性，过期自动刷新
 *
 * @author lujingpo
 * @date 2021/2/5
 */
@EqualsAndHashCode(callSuper = true)
@Data
@Slf4j
public class SelfUseDouYinClient extends DefaultDouYinClient{

    public SelfUseDouYinClient(IDouYinConfigStorage configStorage) {
        super(configStorage);
    }


    @Override
    public <T extends BaseDouYinResponse> T execute(DouYinRequest<T> request) throws ApiException {
        return this.executeWrapper(request);
    }

    /**
     * 获取accessToken
     *
     * @param forceRefresh 是否强制刷新
     * @return String
     */
    @Override
    public String getAccessToken(boolean forceRefresh) {
        final IDouYinConfigStorage configStorage = getConfigStorage();
        if (!configStorage.isAccessTokenExpired() && !forceRefresh) {
            return configStorage.getAccessToken();
        }
        Lock lock = configStorage.getAccessTokenLock();
        lock.lock();
        try {

            // 拿到锁之后，再判断一次，防止重刷
            if (!configStorage.isAccessTokenExpired() && !forceRefresh) {
                return configStorage.getAccessToken();
            }

            OauthResponse oauthResponse;
            if (configStorage.isRefreshTokenExpired()) {
                oauthResponse = selfAccess(configStorage.getShopId());
            } else {
                try {
                    // 刷新失败后调用生成token的方法
                    oauthResponse = refreshAccessToken(configStorage.getRefreshToken());
                } catch (ApiException e) {
                    oauthResponse = selfAccess(configStorage.getShopId());
                }
            }

            configStorage.updateAccessToken(oauthResponse.getAccessToken(), oauthResponse.getRefreshToken(), oauthResponse.getExpiresIn());

        } catch (ApiException e) {
            log.error("刷新用户{}token异常", this.appKey, e);
            throw new ApiRuntimeException("刷新用户token异常");
        } finally {
            lock.unlock();
        }

        return configStorage.getAccessToken();
    }


    /**
     * 自用型应用授权
     *
     * @link https://op.jinritemai.com/docs/guide-docs/9/21
     * @return 获取token
     */
    private OauthResponse selfAccess(String shopId) throws ApiException {
        return code2Access(null, shopId);
    }
}
